package com.ikingtech.framework.sdk.office.utils;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import jakarta.servlet.http.HttpServletResponse;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

/**
 * excel模板工具类
 *
 * @author lqb
 */
public class ExcelTemplateUtil {

    /**
     * 获取模板输入流
     *
     * @param templatePath 模板名称
     * @return 执行结果
     * @author lqb
     */
    public static InputStream getTemplateInputStream(String templatePath) {
        if (templatePath.startsWith("http://") || templatePath.startsWith("https://")) {
            try {
                URL url = new URL(templatePath);
                //获取链接
                HttpURLConnection uc = (HttpURLConnection) url.openConnection();
                uc.setDoInput(true);//设置是否要从 URL 连接读取数据,默认为true
                uc.connect();
                return uc.getInputStream();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return ExcelTemplateUtil.class.getClassLoader().getResourceAsStream(templatePath);
    }

    /**
     * 按模板填写excel
     *
     * @return 执行结果
     * @author lqb
     */
    public static byte[] makeExcelByFill(InputStream tempInputStream, JSONArray fillData, JSONObject data) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try (ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(tempInputStream).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行，然后下面的数据往后移动。默认 是false，会直接使用下一行，如果没有则创建。
            // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了，所以慎用
            // 简单的说 如果你的模板有list,且list不是最后一行，下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
            // 如果数据量大 list不是最后一行 参照下一个
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(data, writeSheet);
            excelWriter.fill(fillData, fillConfig, writeSheet);
            tempInputStream.close();
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return outputStream.toByteArray();
    }

    /**
     * 文件流输出excel
     *
     * @param fileBytes 文件字节
     * @param fileName  文件名
     * @param response  回答
     * @author lqb
     */
    public static void writeExcel(byte[] fileBytes, String fileName, HttpServletResponse response) {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
            response.getOutputStream().write(fileBytes);
            response.getOutputStream().flush();
            response.getOutputStream().close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 文件流输出excel
     *
     * @param templatePath 模板路径
     * @param fillData     填充数据
     * @param data         数据
     * @param fileName     文件名
     * @param response     回答
     * @author lqb
     */
    public static void writeExcel(String templatePath, JSONArray fillData, JSONObject data, String fileName, HttpServletResponse response) {
        writeExcel(makeExcelByFill(getTemplateInputStream(templatePath), fillData, data), fileName, response);
    }

}
